package com.taysear.parcel;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.taysear.parcel.domain.Account;
import com.taysear.parcel.domain.Loadingsheet;
import com.taysear.parcel.domain.Parcel;
import com.taysear.parcel.domain.ParcelDetail;
import com.taysear.parcel.domain.ParcelHistory;
import com.taysear.parcel.domain.ParcelStatus;
import com.taysear.parcel.domain.PaymentMode;
import com.taysear.parcel.util.Constants;
import com.taysear.parcel.util.Util;
import com.vaadin.addon.tableexport.ExportableColumnGenerator;
import com.vaadin.data.Container;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.event.DataBoundTransferable;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.event.dd.acceptcriteria.And;
import com.vaadin.event.dd.acceptcriteria.ClientSideCriterion;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.themes.Runo;

@SuppressWarnings("serial")
public class ParcelTable extends Table {

	private ParcelApplication app;
	private Integer selectedLoadingsheet;
	
	public ParcelTable() {
		super();
	}

	public ParcelTable(ParcelApplication app, String title, Container container, String [] columns, Integer selectedLoadingsheet) {
		super(title, container);
		this.app = app;
		this.selectedLoadingsheet = selectedLoadingsheet;
		
		addGeneratedColumn("Date", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("date").getValue() != null) {
		          return getParcelDate(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("date").getValue() != null) {
				  return getParcelDate(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Sender", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getSender(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getSender(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Sender Tel", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getSenderTel(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getSenderTel(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Receiver", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getReceiver(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getReceiver(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Receiver Tel", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getReceiverTel(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getReceiverTel(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Origin", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getOrigin(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getOrigin(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Destination", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
				  return getDestination(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelDetail").getValue() != null) {
		          return getDestination(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Loadingsheet", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("loadingsheet").getValue() != null) {
				  return getLoadingsheet(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("loadingsheet").getValue() != null) {
		          return getLoadingsheet(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Status", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelStatus").getValue() != null) {
				  return getStatus(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelStatus").getValue() != null) {
		          return getStatus(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Waybill No", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("waybillNumber").getValue() != null) {
				  return getWaybillNumber(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("waybillNumber").getValue() != null) {
		          return getWaybillNumber(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Qty", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("quantity").getValue() != null) {
				  return getQuantity(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("quantity").getValue() != null) {
		          return getQuantity(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Cashier", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("parcelHistories").getValue() != null) {
				  return getCashier(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("parcelHistories").getValue() != null) {
		          return getCashier(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Pay Mode", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("paymentMode").getValue() != null) {
				  return getPaymentMode(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("paymentMode").getValue() != null) {
		          return getPaymentMode(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Account", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("account").getValue() != null) {
				  return getAccount(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("account").getValue() != null) {
		          return getAccount(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Weight", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("weight").getValue() != null) {
				  return getWeight(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("weight").getValue() != null) {
		          return getWeight(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("VAT", new ExportableColumnGenerator()
		{
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("vatAmount").getValue() != null) {
				  return getVatAmount(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("vatAmount").getValue() != null) {
		          return getVatAmount(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addGeneratedColumn("Amount", new ExportableColumnGenerator() {
		  @Override
		  public Property getGeneratedProperty(Object itemId, Object columnId)
		    {
			  if (getItem(itemId).getItemProperty("amount").getValue() != null) {
				  return getAmount(itemId);
		      }
		      return null;
		  }
		  @Override
		  public Component generateCell(Table source, Object itemId, Object columnId)
		  {
			  if (getItem(itemId).getItemProperty("amount").getValue() != null) {
		          return getAmount(itemId);
		      }
		      return null;
		  }

		  @Override public Class<?> getType(){return String.class;}
		});
		
		addStyleName(Runo.TABLE_SMALL);
        setVisibleColumns(columns);
		setSizeUndefined();
		setImmediate(true);
		setMultiSelectMode(MultiSelectMode.SIMPLE);
		setPageLength(Constants.PARCEL_TABLE_PAGE_LENGTH);
		setImmediate(true);
	}
	
	public void initializeTable(final ClientSideCriterion acceptCriterion, final BeanItemContainer<Parcel> tableContainer) {

		// Handle drop in table: move hardware item or subtree to the table
        setDragMode(TableDragMode.MULTIROW);
        setSizeFull();
        setDropHandler(new DropHandler() {
            public void drop(DragAndDropEvent dropEvent) {
            	// criteria verify that this is safe
                DataBoundTransferable dataBound = (DataBoundTransferable) dropEvent.getTransferable();
                Container sourceContainer = dataBound.getSourceContainer();
                ParcelTable des = (ParcelTable) dropEvent.getTargetDetails().getTarget();
                ParcelTable source = (ParcelTable) dataBound.getSourceComponent();
                Set<Parcel> values =  (Set<Parcel>) source.getValue();
                if(selectedLoadingsheet != null && selectedLoadingsheet != 0){
                	Loadingsheet loadingsheet = app.em.find(Loadingsheet.class, selectedLoadingsheet);
                	for (Parcel parcel : values) {
		                parcel.setLoadingsheet(loadingsheet);
		                tableContainer.addItem(parcel);
		                sourceContainer.removeItem(parcel);
	                }
                } else {
                	for (Parcel parcel : values) {
		                tableContainer.addItem(parcel);
		                sourceContainer.removeItem(parcel);
	                }
                }
            }

            public AcceptCriterion getAcceptCriterion() {
                return new And(acceptCriterion, AcceptItem.ALL);
            }
        });
    }
	
	private Label getParcelDate(Object itemId){
		Label l = new Label();
        l.setValue(app.formatDateWithoutTime((Date) getItem(itemId).getItemProperty("date").getValue()));
        l.setSizeUndefined();
        return l;
	}
	
	private Label getSender(Object itemId){
		Label l = new Label();
        ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getSender() == null ? p.getSenderName() : p.getSender().getLastname());
        l.setSizeUndefined();
	    return l;
	}
	
	private Label getSenderTel(Object itemId){
		Label l = new Label();
        ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getSenderTel());
        l.setSizeUndefined();
	    return l;
	}
	
	private Label getReceiver(Object itemId){
		Label l = new Label();
		ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getReceiver() == null ? p.getReceiverName() : p.getSender().getLastname());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getReceiverTel(Object itemId){
		Label l = new Label();
        ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getReceiverTel());
        l.setSizeUndefined();
	    return l;
	}
	
	private Label getOrigin(Object itemId){
		Label l = new Label();
		ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getSenderSubstation().getName());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getDestination(Object itemId){
		Label l = new Label();
		ParcelDetail p =(ParcelDetail) getItem(itemId).getItemProperty("parcelDetail").getValue();
        l.setValue(p.getReceiverSubstation().getName());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getLoadingsheet(Object itemId){
		Label l = new Label();
        Loadingsheet ls =(Loadingsheet) getItem(itemId).getItemProperty("loadingsheet").getValue();
        l.setValue(ls.getLoadingsheetId());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getStatus(Object itemId){
		Label l = new Label();
		ParcelStatus ps =(ParcelStatus) getItem(itemId).getItemProperty("parcelStatus").getValue();
        l.setValue(ps.getDescription());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getQuantity(Object itemId){
		Label l = new Label();
        l.setValue(getItem(itemId).getItemProperty("quantity").getValue());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getWaybillNumber(Object itemId){
		Label l = new Label();
        l.setValue(getItem(itemId).getItemProperty("waybillNumber").getValue());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getCashier(Object itemId){
		Label l = new Label();
  	  	List<ParcelHistory> ph =(List<ParcelHistory>) getItem(itemId).getItemProperty("parcelHistories").getValue();
        Iterator<ParcelHistory> pit = ph.iterator();
        ParcelHistory p = pit.next();
        l.setValue(p.getUser().getEmployee().getFirstname() +" "+p.getUser().getEmployee().getLastname());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getPaymentMode(Object itemId){
		Label l = new Label();
        PaymentMode pm =(PaymentMode) getItem(itemId).getItemProperty("paymentMode").getValue();
        l.setValue(pm.getDescription());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getAccount(Object itemId){
		Label l = new Label();
		Account ac = (Account) getItem(itemId).getItemProperty("account").getValue();
        l.setValue(ac);
        l.setSizeUndefined();
        return l;
	}
	
	private Label getWeight(Object itemId){
		Label l = new Label();
        l.setValue(getItem(itemId).getItemProperty("weight").getValue());
        l.setSizeUndefined();
        return l;
	}
	
	private Label getVatAmount(Object itemId){
		Label l = new Label();
        l.setValue(Util.formatMoney(getItem(itemId).getItemProperty("vatAmount").getValue().toString()));
        l.setSizeUndefined();
        return l;
	}
	
	private Label getAmount(Object itemId){
		Label l = new Label();
        l.setValue(Util.formatMoney(getItem(itemId).getItemProperty("amount").getValue().toString()));
        l.setSizeUndefined();
        return l;
	}
}